home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gamers Delight 2
/
Gamers Delight 2.iso
/
Aminet
/
game
/
role
/
pinfocom_3_0.lha
/
Source
/
amiga_console.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-22
|
89KB
|
4,342 lines
/* amiga_console.c
*
* ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
* Copyright (C) 1987-1992 InfoTaskForce
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to the
* Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Header: RCS/amiga_console.c,v 3.0 1992/10/21 16:56:19 pds Stab $
*/
#ifndef _AMIGA_GLOBAL_H
#include "amiga_global.h"
#endif /* !_AMIGA_GLOBAL_H */
/* ConCharWidth(const UBYTE Char):
*
* Calculate the pixel width of a glyph.
*/
UWORD
ConCharWidth(const UBYTE Char)
{
return((UWORD)TextLength(RPort,(STRPTR)&Char,1));
}
/* ConCursorOff():
*
* Turn the terminal cursor on.
*/
VOID
ConCursorOff()
{
/* Is it still enabled? */
if(CursorEnabled)
{
LONG Left = LastCursorX + Window -> BorderLeft,
Top = LastCursorY + Window -> BorderTop;
/* Turn on xor operation. */
SetDrMd(RPort,JAM1 | COMPLEMENT);
/* Complement all planes. */
SetAPen(RPort,(1 << Depth) - 1);
/* Is the window inactive? */
if(!WindowIsActive)
{
/* Set the cross-hatch pattern. */
SetAfPt(RPort,&ChipData[CHIPDATA_PATTERN],1);
/* Render the cursor data. */
RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
/* Reset the pattern. */
SetAfPt(RPort,NULL,0);
}
else
RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
/* Reset the drawing mode. */
SetDrMd(RPort,JAM2);
/* Reset the drawing pen. */
SetAPen(RPort,ConTextPen);
/* It's turned off now. */
CursorEnabled = FALSE;
}
}
/* ConCursorOn(const int New):
*
* Turn the terminal cursor off.
*/
VOID
ConCursorOn(const int New)
{
/* Is it still disabled? */
if(!CursorEnabled)
{
LONG Left = CursorX + Window -> BorderLeft,
Top = CursorY + Window -> BorderTop;
/* Remember new cursor width. */
switch(New)
{
case CURSOR_NOCHANGE: break;
case CURSOR_AVERAGE: NewCursorWidth = DefaultCursorWidth;
break;
default: NewCursorWidth = New;
break;
}
/* Turn on xor operation. */
SetDrMd(RPort,JAM1 | COMPLEMENT);
/* Complement all planes. */
SetAPen(RPort,(1 << Depth) - 1);
/* Is the window inactive? */
if(!WindowIsActive)
{
/* Set the cross-hatch pattern. */
SetAfPt(RPort,&ChipData[CHIPDATA_PATTERN],1);
/* Render the cursor data. */
RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
/* Reset the pattern. */
SetAfPt(RPort,NULL,0);
}
else
RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
/* Reset the drawing mode. */
SetDrMd(RPort,JAM2);
/* Reset the drawing pen. */
SetAPen(RPort,ConTextPen);
/* Remember cursor width. */
OldCursorWidth = NewCursorWidth;
/* It's turn on now. */
CursorEnabled = TRUE;
/* Remember cursor position. */
LastCursorX = CursorX;
LastCursorY = CursorY;
}
}
/* ConMove(const int Delta,const int New):
*
* Move the cursor.
*/
VOID
ConMove(const int Delta,const int New)
{
/* If the cursor is still enabled, turn it
* off before repositioning it.
*/
if(CursorEnabled)
{
/* Turn the cursor off. */
ConCursorOff();
/* Move it. */
CursorX += Delta;
/* Turn the cursor back on. */
ConCursorOn(New);
}
else
{
CursorX += Delta;
switch(New)
{
case CURSOR_NOCHANGE: NewCursorWidth = OldCursorWidth;
break;
case CURSOR_AVERAGE: NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
break;
default: NewCursorWidth = OldCursorWidth = New;
break;
}
}
}
/* ConSet(const int X,const int Y,const int New):
*
* Place the cursor at a specific position.
*/
VOID
ConSet(const int X,const int Y,const int New)
{
/* If the cursor is still enabled, turn it
* off before repositioning it.
*/
if(CursorEnabled)
{
/* Turn the cursor off. */
ConCursorOff();
/* Move drawing pen. */
Move(RPort,X + Window -> BorderLeft,Y + ThisFont -> tf_Baseline + Window -> BorderTop);
/* Position the cursor. */
CursorX = X;
CursorY = Y;
/* Turn the cursor back on. */
ConCursorOn(New);
}
else
{
/* Remember new cursor width. */
switch(New)
{
case CURSOR_NOCHANGE: NewCursorWidth = OldCursorWidth;
break;
case CURSOR_AVERAGE: NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
break;
default: NewCursorWidth = OldCursorWidth = New;
break;
}
/* Move drawing pen. */
Move(RPort,X + Window -> BorderLeft,Y + ThisFont -> tf_Baseline + Window -> BorderTop);
/* Position the cursor. */
CursorX = X;
CursorY = Y;
}
}
/* ConClearEOL():
*
* Clear to end of current line.
*/
VOID
ConClearEOL()
{
/* Is there anything to clear? */
if(CursorX < WindowWidth)
{
/* Turn the cursor off before the line is cleared. */
if(CursorEnabled)
{
/* Turn the cursor off. */
ConCursorOff();
/* Clear the remaining line. */
SetAPen(RPort,ConBackPen);
RectFill(RPort,CursorX + Window -> BorderLeft,CursorY + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),CursorY + Window -> BorderTop + TextFontHeight - 1);
SetAPen(RPort,ConTextPen);
/* Turn the cursor back on. */
ConCursorOn(CURSOR_NOCHANGE);
}
else
{
SetAPen(RPort,ConBackPen);
RectFill(RPort,CursorX + Window -> BorderLeft,CursorY + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),CursorY + Window -> BorderTop + TextFontHeight - 1);
SetAPen(RPort,ConTextPen);
}
}
}
/* ConCharBackspace(const int Delta,const int New):
*
* Move the cursor one glyph back.
*/
VOID
ConCharBackspace(const int Delta,const int New)
{
RedrawInputLine = TRUE;
CursorX -= Delta;
switch(New)
{
case CURSOR_NOCHANGE: NewCursorWidth = OldCursorWidth;
break;
case CURSOR_AVERAGE: NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
break;
default: NewCursorWidth = OldCursorWidth = New;
break;
}
}
/* ConCharDelete(const int New):
*
* Delete the character under the cursor.
*/
VOID
ConCharDelete(const int New)
{
RedrawInputLine = TRUE;
switch(New)
{
case CURSOR_NOCHANGE: NewCursorWidth = OldCursorWidth;
break;
case CURSOR_AVERAGE: NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
break;
default: NewCursorWidth = OldCursorWidth = New;
break;
}
}
/* ConCharInsert(const UBYTE Char):
*
* Insert a character at the current cursor position.
*/
VOID
ConCharInsert(const UBYTE Char)
{
RedrawInputLine = TRUE;
CursorX += ConCharWidth(Char);
}
/* ConScrollUp():
*
* Scroll the terminal contents one line up.
*/
VOID
ConScrollUp()
{
/* Inside the status line the cursor is always
* disabled.
*/
if(ConOutputWindow)
ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),ConNumStatusLines * TextFontHeight);
else
{
/* Is the cursor enabled? */
if(CursorEnabled)
{
/* Turn the cursor off. */
ConCursorOff();
/* Scroll the terminal contents up. */
if(gflags . pr_status || ConNumStatusLines > 1)
ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,ConNumStatusLines * TextFontHeight + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
else
ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
/* Reposition the cursor. */
CursorX = 0;
CursorY = TextFontHeight * (ConNumLines - 1);
/* Turn it on again. */
ConCursorOn(CURSOR_NOCHANGE);
}
else
{
/* Scroll the terminal contents up. */
if(gflags . pr_status || ConNumStatusLines > 1)
ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,ConNumStatusLines * TextFontHeight + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
else
ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
/* Reposition the cursor. */
CursorX = 0;
CursorY = TextFontHeight * (ConNumLines - 1);
}
}
}
/* ConWrite(const char *Line,LONG Len,LONG Indent):
*
* Output a text on the terminal.
*/
VOID
ConWrite(const char *Line,LONG Len,LONG Indent)
{
/* Just like console.device, determine the
* text length if -1 is passed in as the
* length.
*/
if(Len == -1)
Len = strlen(Line);
/* Is there anything to print? */
if(Len)
{
/* Is the cursor still enabled? */
if(CursorEnabled)
{
/* Turn off the cursor. */
ConCursorOff();
/* Print the text. */
Move(RPort,Indent + CursorX + Window -> BorderLeft,CursorY + ThisFont -> tf_Baseline + Window -> BorderTop);
Text(RPort,(STRPTR)Line,Len);
/* Move up. */
CursorX += TextLength(RPort,(STRPTR)Line,Len);
/* Turn the cursor back on. */
ConCursorOn(CURSOR_NOCHANGE);
}
else
{
/* Print the text. */
Move(RPort,Indent + CursorX + Window -> BorderLeft,CursorY + ThisFont -> tf_Baseline + Window -> BorderTop);
Text(RPort,(STRPTR)Line,Len);
/* Move up. */
CursorX += TextLength(RPort,(STRPTR)Line,Len);
}
}
}
/* ConRedraw(const int X,const int Y,const STRPTR String,const int Len):
*
* Redraw the input string.
*/
VOID
ConRedraw(const int X,const int Y,const STRPTR String,const int Len)
{
/* Determine width in pixels. */
int Width = TextLength(RPort,(STRPTR)String,Len);
/* Turn the cursor off. */
ConCursorOff();
/* Redraw the input string. */
Move(RPort,X + Window -> BorderLeft,Y + ThisFont -> tf_Baseline + Window -> BorderTop);
Text(RPort,(STRPTR)String,Len);
/* Clear to end of line. */
if(Width < WindowWidth)
{
SetAPen(RPort,ConBackPen);
RectFill(RPort,X + Width + Window -> BorderLeft,Y + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Y + Window -> BorderTop + TextFontHeight - 1);
SetAPen(RPort,ConTextPen);
}
/* Turn the cursor back on. */
ConCursorOn(CURSOR_NOCHANGE);
}
/* ConSetColour(const int Colour):
*
* Set the text rendering colours. If running on a monochrome
* display, the colours will be mapped to text style attributes.
*/
VOID
ConSetColour(const int Colour)
{
/* Are we running on a monochrome display? */
Bool IsMono = (Depth == 1 || !NewOS);
/* The following code decides which text rendering colour
* to set.
*/
switch(Colour)
{
/* Text input colour. */
case COLOUR_INPUT: if(IsMono)
{
SetAPen(RPort,ConTextPen = 1);
SetBPen(RPort,ConBackPen = 0);
SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
}
else
{
SetAPen(RPort,ConTextPen = 2);
SetBPen(RPort,ConBackPen = 0);
}
break;
/* Status line colour. */
case COLOUR_STATUS: if(IsMono)
{
SetAPen(RPort,ConTextPen = 0);
SetBPen(RPort,ConBackPen = 1);
SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
}
else
{
SetAPen(RPort,ConTextPen = 2);
SetBPen(RPort,ConBackPen = 3);
}
break;
/* Error message colour. */
case COLOUR_ERROR: if(IsMono)
{
SetAPen(RPort,ConTextPen = 1);
SetBPen(RPort,ConBackPen = 0);
SetSoftStyle(RPort,FSF_UNDERLINED,AskSoftStyle(RPort));
}
else
{
SetAPen(RPort,ConTextPen = 3);
SetBPen(RPort,ConBackPen = 0);
}
break;
/* Special emphasis colour. */
case COLOUR_SPECIAL: if(IsMono)
{
SetAPen(RPort,ConTextPen = 1);
SetBPen(RPort,ConBackPen = 0);
SetSoftStyle(RPort,FSF_BOLD,AskSoftStyle(RPort));
}
else
{
SetAPen(RPort,ConTextPen = 2);
SetBPen(RPort,ConBackPen = 0);
}
break;
/* Standard text colour. */
default: SetAPen(RPort,ConTextPen = 1);
SetBPen(RPort,ConBackPen = 0);
if(IsMono)
SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
break;
}
}
/* ConSetKey(const int Key,const STRPTR String,const int Len):
*
* Set a specific function key.
*/
VOID
ConSetKey(const int Key,const STRPTR String,const int Len)
{
/* Is the new string longer than the old one? */
if(FunctionKeys[Key] . sb_Len < Len)
{
/* Free previous key assignment. */
free(FunctionKeys[Key] . sb_Buffer);
/* Create new string buffer. */
if(FunctionKeys[Key] . sb_Buffer = (char *)malloc(Len + 1))
{
/* Copy the key string. */
memcpy(FunctionKeys[Key] . sb_Buffer,String,Len);
/* Provide null-termination. */
FunctionKeys[Key] . sb_Buffer[Len] = 0;
/* Set string length. */
FunctionKeys[Key] . sb_Len = Len;
}
else
FunctionKeys[Key] . sb_Len = 0;
}
else
{
/* Install new string. */
if(Len)
{
/* Copy the key string. */
memcpy(FunctionKeys[Key] . sb_Buffer,String,Len);
/* Provide null-termination. */
FunctionKeys[Key] . sb_Buffer[Len] = 0;
}
else
{
/* Zero length, free previous buffer
* assignment.
*/
if(FunctionKeys[Key] . sb_Buffer)
{
/* Free the buffer. */
free(FunctionKeys[Key] . sb_Buffer);
/* Clear address pointer. */
FunctionKeys[Key] . sb_Buffer = NULL;
}
}
/* Install new length. */
FunctionKeys[Key] . sb_Len = Len;
}
}
/* ConCloseLibs():
*
* Close required system libraries.
*/
VOID
ConCloseLibs()
{
if(IntuitionBase)
{
CloseLibrary((struct Library *)IntuitionBase);
IntuitionBase = NULL;
}
if(GfxBase)
{
CloseLibrary((struct Library *)GfxBase);
GfxBase = NULL;
}
if(DiskfontBase)
{
CloseLibrary(DiskfontBase);
DiskfontBase = NULL;
}
if(AslBase)
{
CloseLibrary(AslBase);
AslBase = NULL;
}
if(IconBase)
{
CloseLibrary(IconBase);
IconBase = NULL;
}
if(IFFParseBase)
{
CloseLibrary(IFFParseBase);
IFFParseBase = NULL;
}
if(GadToolsBase)
{
CloseLibrary(GadToolsBase);
GadToolsBase = NULL;
}
if(UtilityBase)
{
CloseLibrary(UtilityBase);
UtilityBase = NULL;
}
if(WorkbenchBase)
{
CloseLibrary(WorkbenchBase);
WorkbenchBase = NULL;
}
}
/* ConOpenLibs():
*
* Open required system libraries.
*/
Bool
ConOpenLibs()
{
if(!LibsOpened)
{
/* Remember default window pointer. */
WindowPtr = ThisProcess -> pr_WindowPtr;
/* Make sure that the cleanup routine gets called on exit. */
if(atexit(ConCloseLibs))
return(FALSE);
/* Open intuition.library. */
if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIBRARY_MINIMUM)))
return(FALSE);
/* Open graphics.library. */
if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",LIBRARY_MINIMUM)))
return(FALSE);
DiskfontBase = OpenLibrary("diskfont.library",LIBRARY_MINIMUM);
/* Which operating system revision is this
* machine currently running?
*/
if(NewOS = (IntuitionBase -> LibNode . lib_Version >= LIB_VERSION))
{
/* Open asl.library (file requester routines). */
if(!(AslBase = OpenLibrary("asl.library",LIB_VERSION)))
return(FALSE);
/* Open icon.library (icon file routines). */
if(!(IconBase = OpenLibrary("icon.library",LIB_VERSION)))
return(FALSE);
/* Open utility.library (string comparison routines). */
if(!(UtilityBase = OpenLibrary("utility.library",LIB_VERSION)))
return(FALSE);
/* Open gadtools.library (menu and gadget creation routines). */
if(!(GadToolsBase = OpenLibrary("gadtools.library",LIB_VERSION)))
return(FALSE);
/* Open iffparse.library (iff file parsing routines). */
if(!(IFFParseBase = OpenLibrary("iffparse.library",LIB_VERSION)))
return(FALSE);
/* Open workbench.library (appwindow routines). */
WorkbenchBase = OpenLibrary("workbench.library",LIB_VERSION);
}
else
IconBase = OpenLibrary("icon.library",LIBRARY_MINIMUM);
}
return(LibsOpened = TRUE);
}
/* ConCleanup():
*
* Free all resources.
*/
VOID
ConCleanup()
{
/* Free the sound data. */
SoundExit();
/* Close the clipboard. */
ClipClose();
/* Free the timer request. */
if(TimeRequest)
{
/* Did we succeed in opening the device? */
if(TimeRequest -> tr_node . io_Device)
{
/* Is the time request still pending? If so, abort it. */
if(!CheckIO((struct IORequest *)TimeRequest))
AbortIO((struct IORequest *)TimeRequest);
/* Remove the request. */
WaitIO((struct IORequest *)TimeRequest);
/* Close the device. */
CloseDevice((struct IORequest *)TimeRequest);
}
/* Free the request. */
DeleteExtIO((struct IORequest *)TimeRequest);
}
/* Free the timer port. */
if(TimePort)
DeletePort(TimePort);
/* Free the console request. */
if(ConRequest)
{
/* Did we open the device? If so, close it. */
if(ConRequest -> io_Device)
CloseDevice((struct IORequest *)ConRequest);
/* Free the memory. */
FreeMem(ConRequest,sizeof(struct IOStdReq));
}
/* Free the input conversion buffer. */
if(InputEventBuffer)
FreeMem(InputEventBuffer,INPUT_LENGTH);
/* Free the fake inputevent. */
if(InputEvent)
FreeMem(InputEvent,sizeof(struct InputEvent));
/* Remove appwindow link. */
if(WorkbenchWindow)
RemoveAppWindow(WorkbenchWindow);
/* Remove appwindow msgport and any pending messages. */
if(WorkbenchPort)
{
struct Message *Message;
while(Message = GetMsg(WorkbenchPort))
ReplyMsg(Message);
DeletePort(WorkbenchPort);
}
/* Close the window. */
if(Window)
{
/* Cosmeticism. */
if(Screen)
ScreenToBack(Screen);
/* Remove the pull-down menus. */
if(Menu)
ClearMenuStrip(Window);
/* Really close the window. */
CloseWindow(Window);
}
/* Free the menu strip. */
if(Menu)
FreeMenus(Menu);
/* Free the chip memory buffer. */
if(ChipData)
FreeMem(ChipData,sizeof(UWORD) * (sizeof(StopwatchData) + 2));
/* Free the visual information buffer. */
if(VisualInfo)
FreeVisualInfo(VisualInfo);
/* Close the custom screen if any. */
if(Screen)
CloseScreen(Screen);
/* Close the disk fonts if any. */
if(TextFont)
CloseFont(TextFont);
if(ListFont)
CloseFont(ListFont);
/* Free the file requester. */
if(GameFileRequest)
FreeAslRequest(GameFileRequest);
/* If not already done, release the lock on the default
* public screen.
*/
if(DefaultScreen)
UnlockPubScreen(NULL,DefaultScreen);
/* Reset the DOS requester location. */
if(ThisProcess)
ThisProcess -> pr_WindowPtr = WindowPtr;
}
/* ConSetup():
*
* Set up console interface.
*/
Bool
ConSetup()
{
struct IBox ZoomBox;
UWORD Pen = (UWORD)~0,
Width;
WORD MinHeight,
MinWidth;
UBYTE Char;
ULONG Total = 0,
Count = 0;
Bool UseFont = FALSE;
/* Open system libraries. */
if(!ConOpenLibs())
return(FALSE);
/* Create the console info. */
if(!(ConRequest = (struct IOStdReq *)AllocMem(sizeof(struct IOStdReq),MEMF_ANY|MEMF_CLEAR)))
return(FALSE);
/* Open console.device and extract the device base pointer. */
if(OpenDevice("console.device",CONU_LIBRARY,(struct IORequest *)ConRequest,NULL))
return(FALSE);
ConsoleDevice = ConRequest -> io_Device;
/* Create the input event auxilary buffers. */
if(!(InputEventBuffer = (STRPTR)AllocMem(INPUT_LENGTH,MEMF_ANY)))
return(FALSE);
if(!(InputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_ANY|MEMF_CLEAR)))
return(FALSE);
/* Create timer reply port. */
if(!(TimePort = CreatePort(NULL,0)))
return(FALSE);
/* Create timer request. */
if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))))
return(FALSE);
/* Open timer.device */
if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimeRequest,0))
return(FALSE);
/* Allocate and set up chip memory data area. */
if(!(ChipData = (UWORD *)AllocMem(sizeof(UWORD) * (sizeof(StopwatchData) + 2),MEMF_CHIP)))
return(FALSE);
/* Fill in the cross-hatch pattern. */
ChipData[CHIPDATA_PATTERN ] = 0x5555;
ChipData[CHIPDATA_PATTERN+1] = 0xAAAA;
/* Fill in the mouse pointer data. */
CopyMem((BYTE *)StopwatchData,(BYTE *)&ChipData[CHIPDATA_POINTER],sizeof(StopwatchData));
/* Are we to use special fonts? */
if(ListFontName[0] && TextFontName[0] && FontSize && DiskfontBase)
{
/* Tack on the ".font" suffix. */
strcat(ListFontName,".font");
strcat(TextFontName,".font");
/* Set up the fixed width (`list') font. */
ListFontAttr . ta_Name = ListFontName;
ListFontAttr . ta_YSize = FontSize;
ListFontAttr . ta_Style = FS_NORMAL;
ListFontAttr . ta_Flags = FPF_DISKFONT | FPF_DESIGNED;
/* Set up the proportional-spaced (`text') font. */
TextFontAttr . ta_Name = TextFontName;
TextFontAttr . ta_YSize = FontSize;
TextFontAttr . ta_Style = FS_NORMAL;
TextFontAttr . ta_Flags = FPF_DISKFONT | FPF_DESIGNED | FPF_PROPORTIONAL;
/* Try to open the fonts. */
if((ListFont = OpenDiskFont(&ListFontAttr)) && (TextFont = OpenDiskFont(&TextFontAttr)))
UseFont = TRUE;
}
/* Are we running under control of Kickstart 2.04 or higher? */
if(NewOS)
{
/* Obtain a lock on the default public screen,
* we will try to clone it later.
*/
if(!(DefaultScreen = LockPubScreen(NULL)))
return(FALSE);
/* Are we to open a custom screen? */
if(UseCustomScreen)
{
ULONG DefaultMode,
Mode;
/* Obtain the default screen display mode. */
DefaultMode = GetVPModeID(&DefaultScreen -> ViewPort);
/* Build new display mode ID by looking
* at the default screen display mode
* properties.
*/
if((DefaultMode & LACE) || ((DefaultMode & MONITOR_ID_MASK) == A2024_MONITOR_ID))
Mode = HIRESLACE_KEY;
else
Mode = HIRES_KEY;
/* Determine new screen depth, don't use more
* bit planes than necessary, though.
*/
if((Depth = DefaultScreen -> RastPort . BitMap -> Depth) > 2)
Depth = 2;
/* Open the custom screen. */
if(!(Screen = OpenScreenTags(NULL,
SA_Depth, Depth,
SA_DisplayID, Mode,
SA_Overscan, OSCAN_TEXT,
SA_Pens, &Pen,
UseFont ? TAG_IGNORE : SA_SysFont, 1,
UseFont ? SA_Font : TAG_IGNORE, &TextFontAttr,
SA_Title, SCREEN_TITLE,
SA_AutoScroll, TRUE,
SA_Behind, TRUE,
TAG_DONE)))
return(FALSE);
/* Open the window on the custom screen. */
if(!(Window = OpenWindowTags(NULL,
WA_Left, 0,
WA_Top, Screen -> BarHeight + 2,
WA_Width, Screen -> Width,
WA_Height, Screen -> Height - (Screen -> BarHeight + 2),
WA_Borderless, TRUE,
WA_Backdrop, TRUE,
WA_RMBTrap, TRUE,
WA_NoCareRefresh, TRUE,
WA_NewLookMenus, TRUE,
WA_CustomScreen, Screen,
WA_IDCMP, IDCMP_MENUPICK | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW,
TAG_DONE)))
return(FALSE);
}
else
{
UWORD Width,Height;
if(UseFont)
{
Width = DefaultScreen -> WBorLeft + WINDOW_COLUMNS * ListFont -> tf_XSize + DefaultScreen -> WBorRight;
Height = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + ListFont -> tf_YSize * WINDOW_LINES + DefaultScreen -> WBorBottom;
}
else
{
Width = DefaultScreen -> WBorLeft + WINDOW_COLUMNS * DefaultScreen -> RastPort . Font -> tf_XSize + DefaultScreen -> WBorRight;
Height = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize * (WINDOW_LINES + 1) + DefaultScreen -> WBorBottom;
}
/* Set up the alternative window coordinates and size. */
ZoomBox . Left = 0;
ZoomBox . Top = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1;
ZoomBox . Width = DefaultScreen -> Width;
ZoomBox . Height = DefaultScreen -> Height - ZoomBox . Top;
/* Set up the window title. */
strcpy(WindowTitle,FilePart((STRPTR)gflags . filenm));
/* Open the window on the Workbench screen. */
if(!(Window = OpenWindowTags(NULL,
WA_Title, WindowTitle,
WA_Width, Width,
WA_Height, Height,
WA_MaxWidth, Width,
WA_MaxHeight, Height,
WA_MinWidth, Width,
WA_MinHeight, Height,
WA_Zoom, &ZoomBox,
WA_RMBTrap, TRUE,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_Activate, TRUE,
WA_SizeGadget, TRUE,
WA_SizeBBottom, TRUE,
WA_NoCareRefresh, TRUE,
WA_NewLookMenus, TRUE,
WA_CustomScreen, DefaultScreen,
WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_MENUPICK | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW,
TAG_DONE)))
return(FALSE);
else
{
struct DrawInfo *DrawInfo;
if(DrawInfo = GetScreenDrawInfo(Window -> WScreen))
{
Depth = DrawInfo -> dri_Depth;
FreeScreenDrawInfo(Window -> WScreen,DrawInfo);
}
else
Depth = 1;
SetWindowTitles(Window,(STRPTR)~0,SCREEN_TITLE);
}
}
/* Release the lock on the default public screen. */
UnlockPubScreen(NULL,DefaultScreen);
/* Clear the address pointer. */
DefaultScreen = NULL;
/* Allocate the file requester. */
if(!(GameFileRequest = AllocAslRequestTags(ASL_FileRequest,
ASL_LeftEdge, Window -> LeftEdge + Window -> Width / 4,
ASL_TopEdge, Window -> TopEdge + Window -> Height / 4,
ASL_Width, Window -> Width / 2,
ASL_Height, Window -> Height / 2,
TAG_DONE)))
return(FALSE);
/* Obtain visual info on our custom screen. */
if(!(VisualInfo = GetVisualInfo(Window -> WScreen,TAG_DONE)))
return(FALSE);
/* Create the pull-down menus. */
if(!(Menu = CreateMenus(ConMenuConfig,TAG_DONE)))
return(FALSE);
/* Properly layout the menus. */
if(!(LayoutMenus(Menu,VisualInfo,
GTMN_NewLookMenus, TRUE,
GTMN_TextAttr, Window -> WScreen -> Font,
TAG_DONE)))
return(FALSE);
/* Attach the menus to the window. */
SetMenuStrip(Window,Menu);
/* Enable the menus. */
Window -> Flags &= ~WFLG_RMBTRAP;
}
else
{
/* The buffer to hold information on the Workbench screen. */
struct Screen WorkbenchScreen;
/* Screen and window allocation data. */
struct NewScreen NewScreen;
struct NewWindow NewWindow;
/* Clear the new screen structure. */
memset(&NewScreen,0,sizeof(struct NewScreen));
/* Fill in the common data. */
NewScreen . Depth = 1;
NewScreen . DetailPen = 0;
NewScreen . BlockPen = 1;
NewScreen . DefaultTitle = SCREEN_TITLE;
NewScreen . Type = CUSTOMSCREEN | SCREENBEHIND;
if(UseFont)
NewScreen . Font = &TextFontAttr;
/* Get the Workbench screen size and display mode. */
if(GetScreenData((BYTE *)&WorkbenchScreen,sizeof(struct Screen),WBENCHSCREEN,NULL))
{
NewScreen . ViewModes = WorkbenchScreen . ViewPort . Modes;
NewScreen . Height = WorkbenchScreen . Height;
NewScreen . Width = WorkbenchScreen . Width;
}
else
return(FALSE);
/* Clear the new window structure. */
memset(&NewWindow,0,sizeof(struct NewWindow));
/* Fill in the common data. */
NewWindow . LeftEdge = 0;
NewWindow . Width = NewScreen . Width;
NewWindow . DetailPen = (UBYTE)-1;
NewWindow . BlockPen = (UBYTE)-1;
NewWindow . IDCMPFlags = MOUSEBUTTONS | RAWKEY | ACTIVEWINDOW | INACTIVEWINDOW | NEWSIZE | CLOSEWINDOW;
NewWindow . MinWidth = NewWindow . Width;
NewWindow . MinHeight = NewWindow . Height;
NewWindow . MaxWidth = NewWindow . Width;
NewWindow . MaxHeight = NewWindow . Height;
/* Are we to open a custom screen? */
if(UseCustomScreen)
{
/* Default colour palette. */
STATIC UWORD Palette[2] = { 0x000,0xEEE };
/* Open the screen. */
if(!(Screen = OpenScreen(&NewScreen)))
return(FALSE);
/* Set the screen colours. */
LoadRGB4(&Screen -> ViewPort,Palette,2);
/* Set up the remaining window flags. */
NewWindow . TopEdge = Screen -> BarHeight + 1;
NewWindow . Height = Screen -> Height - NewWindow . TopEdge;
NewWindow . Flags = ACTIVATE | RMBTRAP | SMART_REFRESH | NOCAREREFRESH | BORDERLESS | BACKDROP;
NewWindow . Screen = Screen;
NewWindow . Type = CUSTOMSCREEN;
}
else
{
/* Set up the remaining window flags. */
NewWindow . TopEdge = WorkbenchScreen . BarHeight + 1;
NewWindow . Height = NewScreen . Height - NewWindow . TopEdge;
NewWindow . Flags = ACTIVATE | RMBTRAP | SMART_REFRESH | NOCAREREFRESH | WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE;
NewWindow . Title = SCREEN_TITLE;
NewWindow . Type = WBENCHSCREEN;
}
/* Open the window. */
if(!(Window = OpenWindow(&NewWindow)))
return(FALSE);
else
Depth = Window -> RPort -> BitMap -> Depth;
}
/* Let's assume that our window is active now. */
WindowIsActive = TRUE;
/* Did we open a custom screen? */
if(!Screen && WorkbenchBase)
{
/* Create Workbench appwindow msgport. */
if(!(WorkbenchPort = CreatePort(NULL,0)))
return(FALSE);
/* Create Workbench appwindow link. */
if(!(WorkbenchWindow = AddAppWindow(0,0,Window,WorkbenchPort,NULL)))
return(FALSE);
}
/* Determine inner window width. */
WindowWidth = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
/* Obtain rastport pointer. */
RPort = Window -> RPort;
/* Set text rendering mode. */
SetDrMd(RPort,JAM2);
/* Set text colour. */
ConSetColour(COLOUR_TEXT);
/* Get both the screen and system default font. The
* screen font can be a proportional-spaced font
* while the window rastport font is guaranteed
* to be a fixed-width font.
*/
if(UseFont)
{
PropFont = TextFont;
FixedFont = ListFont;
}
else
{
PropFont = Window -> WScreen -> RastPort . Font;
FixedFont = Window -> IFont;
}
/* Obtain the system default font dimensions. */
TextFontHeight = FixedFont -> tf_YSize;
TextFontWidth = 0;
/* Both the proportional-spaced and the fixed-width
* font have to match in height. If this is not the
* case, we will use only the fixed-width font.
*/
if(PropFont -> tf_YSize != FixedFont -> tf_YSize)
PropFont = FixedFont;
/* Set the fixed-width font. */
SetFont(RPort,ThisFont = FixedFont);
/* Look for the widest glyph. */
for(Char = ' ' ; Char <= '~' ; Char++)
{
if((Width = ConCharWidth(Char)) > TextFontWidth)
TextFontWidth = Width;
/* Update width. */
Total += Width;
Count++;
}
/* Set the proportional-spaced font. */
SetFont(RPort,ThisFont = PropFont);
/* Look for the widest glyph. */
for(Char = ' ' ; Char <= '~' ; Char++)
{
if((Width = ConCharWidth(Char)) > TextFontWidth)
TextFontWidth = Width;
/* Update width. */
Total += Width;
Count++;
}
/* Determine the average glyph width. */
DefaultCursorWidth = Total / Count;
/* Determine space character width. */
SpaceWidth = ConCharWidth(' ');
/* Determine window minimum dimensions. */
MinWidth = Window -> BorderLeft + MIN_WINDOW_COLUMNS * TextFontWidth + Window -> BorderRight;
MinHeight = Window -> BorderTop + MIN_WINDOW_LINES * TextFontHeight + Window -> BorderBottom;
/* Set the minimum dimensions if possible. */
if(MinWidth < Window -> Width)
{
if(MinHeight < Window -> Height)
WindowLimits(Window,MinWidth,MinHeight,Window -> WScreen -> Width,Window -> WScreen -> Height);
else
WindowLimits(Window,MinWidth,0,Window -> WScreen -> Width,Window -> WScreen -> Height);
}
else
WindowLimits(Window,0,0,Window -> WScreen -> Width,Window -> WScreen -> Height);
/* Remember initial window width. */
OldWindowWidth = Window -> Width;
OldWindowHeight = Window -> Height;
/* Redirect DOS requesters. */
ThisProcess -> pr_WindowPtr = (APTR)Window;
/* Start the timer. */
TimeRequest -> tr_node . io_Command = TR_ADDREQUEST;
TimeRequest -> tr_time . tv_secs = 0;
TimeRequest -> tr_time . tv_micro = SECOND / 2;
SendIO((struct IORequest *)TimeRequest);
/* Return success. */
return(TRUE);
}
/* ConGetChar(Bool SingleKey):
*
* Read a single character from the console.
*/
UBYTE
ConGetChar(const Bool SingleKey)
{
struct IntuiMessage *IntuiMessage;
ULONG Qualifier,
Class,
Code,
Signals;
LONG Len;
Bool GotName = FALSE;
/* Provide `fake' input in case we are
* returning the result of a function keypress
* or a menu event.
*/
if(InputIndex)
{
/* Did we reach the end of the string?
* If so, clear the index pointer and
* fall through to the input routine.
* If not, return the next character
* in the buffer.
*/
if(*InputIndex)
return(*InputIndex++);
else
{
/* Are we to read input from the clipboard? */
if(ClipInput)
{
LONG Len;
/* Read next data. */
if((Len = ClipRead(InputBuffer,INPUT_LENGTH)) > 0)
{
/* Reset index pointer. */
InputIndex = InputBuffer;
/* Return the next byte. */
return(*InputIndex++);
}
else
{
/* Close the clipboard. */
ClipClose();
}
}
/* Clear the buffer pointer. */
InputIndex = NULL;
}
}
/* Wait for input... */
FOREVER
{
/* Process all incoming messages. */
while(IntuiMessage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
{
/* Remember the menu code. */
Qualifier = IntuiMessage -> Qualifier;
Class = IntuiMessage -> Class;
Code = IntuiMessage -> Code;
/* Conver key code to ANSI character or control sequence. */
if(Class == IDCMP_RAWKEY)
{
InputEvent -> ie_Class = IECLASS_RAWKEY;
InputEvent -> ie_Code = Code;
InputEvent -> ie_Qualifier = Qualifier;
/* Not really an APTR, but let's keep
* it for the sake of compatibility.
*/
InputEvent -> ie_position . ie_addr = *((APTR *)IntuiMessage -> IAddress);
/* Clear the conversion buffer, or the
* conversion result will be appended
* after the current contents.
*/
InputEventBuffer[0] = 0;
/* Convert the event. */
Len = RawKeyConvert(InputEvent,InputEventBuffer,INPUT_LENGTH - 1,NULL);
}
else
Len = 0;
/* Reply the message. */
ReplyMsg((struct Message *)IntuiMessage);
/* Did the window size change? */
if(Class == IDCMP_NEWSIZE)
return(TERM_RESIZE);
/* Did the window become inactive? */
if(Class == IDCMP_INACTIVEWINDOW)
{
/* Turn the cursor off. */
ConCursorOff();
/* Remember that the window is
* inactive now.
*/
WindowIsActive = FALSE;
/* Turn on the (disabled) cursor. */
ConCursorOn(CURSOR_NOCHANGE);
}
/* Did the window become active? */
if(Class == IDCMP_ACTIVEWINDOW)
{
/* Turn the cursor off. */
ConCursorOff();
/* Remember that the window is
* active now.
*/
WindowIsActive = TRUE;
/* Turn on the (enabled) cursor. */
ConCursorOn(CURSOR_NOCHANGE);
}
/* Did the user press the close gadget? */
if(Class == IDCMP_CLOSEWINDOW && !SingleKey)
return(TERM_CLOSE);
/* Did the user press the select button
* and a single keypress is wanted? If so,
* return a blank space.
*/
if(Class == IDCMP_MOUSEBUTTONS && SingleKey && Code == SELECTDOWN)
return(' ');
/* Did the user press a key? */
if(Class == IDCMP_RAWKEY && Len > 0)
{
/* Return a blank space if just a
* keypress is wanted.
*/
if(SingleKey)
return(' ');
else
{
/* Provide null-termination. */
InputEventBuffer[Len] = 0;
/* Is this a numeric pad key
* and was no shift key pressed?
*/
if((Qualifier & IEQUALIFIER_NUMERICPAD) && !(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT|IEQUALIFIER_CAPSLOCK)))
{
/* Key codes and associated cardinal directions. */
STATIC STRPTR Directions[][2] =
{
"8", "north\r",
"9", "ne\r",
"6", "east\r",
"3", "se\r",
"2", "south\r",
"1", "sw\r",
"4", "west\r",
"7", "nw\r",
"[", "in\r",
"]", "out\r",
"+", "up\r",
"-", "down\r"
};
int i;
/* Run down the list of directions. */
for(i = 0 ; i < sizeof(Directions) / (2 * sizeof(STRPTR)) ; i++)
{
/* Does it match the input? */
if(!strcmp(Directions[i][0],InputEventBuffer))
{
/* Use it as fake input. */
InputIndex = Directions[i][1];
/* Return ^X. */
return(TERM_CUT);
}
}
/* Get back to the loop. */
continue;
}
/* Check for special codes, such as
* Shift + Del or Shift + Backspace.
*/
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
/* Delete to end of line? */
if(InputEventBuffer[0] == TERM_DEL)
return(TERM_DELFWD);
/* Delete to start of line? */
if(InputEventBuffer[0] == TERM_BS)
return(TERM_DELBCK);
}
/* Take over the input. */
InputIndex = InputEventBuffer;
/* Return the first character. */
return(*InputIndex++);
}
}
/* Process all menu codes, including
* cases of multiple-selection.
*/
if(Class == IDCMP_MENUPICK)
{
struct MenuItem *Item;
UBYTE Char = 0;
/* Process all menu selections. */
while(Code != MENUNULL)
{
/* Obtain the address of
* the menu item to belong
* to this menu code.
*/
if(Item = ItemAddress(Menu,Code))
{
/* Did we already get
* a suitable menu
* item?
*/
if(!Char)
{
/* Get the new input string. */
if(!(InputIndex = (STRPTR)GTMENUITEM_USERDATA(Item)))
{
/* Is it the `About...' item? */
if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_PROJECT,PROJECTMENU_ABOUT,NOSUB)))
{
/* Turn the cursor off. */
ConCursorOff();
/* Display the information requester. */
ConAbout();
/* Turn the cursor back on. */
ConCursorOn(CURSOR_NOCHANGE);
}
/* Is it the `Script...' item? */
if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_PROJECT,PROJECTMENU_SCRIPT,NOSUB)))
{
/* This is probably the scripting command. */
if(F2_IS_SET(B_SCRIPTING))
InputIndex = (STRPTR)"Unscript\r";
else
InputIndex = (STRPTR)"Script\r";
/* `Fake' a Ctrl-X
* to clear the contents
* of the input line.
*/
Char = TERM_CUT;
}
/* Is it the `Cut' item? */
if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_CUT,NOSUB)))
Char = TERM_CUT;
/* Is it the `Copy' item? */
if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_COPY,NOSUB)))
Char = TERM_COPY;
/* Is it the `Paste' item? */
if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_PASTE,NOSUB)))
{
/* Open the clipboard for reading. */
if(ClipOpen())
{
LONG Len;
/* Read next data. */
if((Len = ClipRead(InputBuffer,INPUT_LENGTH)) > 0)
{
/* Reset index pointer. */
InputIndex = InputBuffer;
/* Return the next byte. */
return(*InputIndex++);
}
/* Close the clipboard. */
ClipClose();
}
}
/* Is it the `Undo' item? */
if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_UNDO,NOSUB)))
Char = TERM_UNDO;
}
else
{
/* `Fake' a Ctrl-X
* to clear the contents
* of the input line.
*/
Char = TERM_CUT;
}
}
/* Proceed to next menu entry. */
Code = Item -> NextSelect;
}
}
/* Did we get anything sensible? If so,
* return immediately.
*/
if(Char)
return(Char);
}
}
/* Check the Workbench appwindow. */
if(WorkbenchPort)
{
struct AppMessage *AppMessage;
while(AppMessage = (struct AppMessage *)GetMsg(WorkbenchPort))
{
/* Do we already have a file name? */
if(!GotName)
{
LONG i;
/* Run down the list of arguments... */
for(i = 0 ; !GotName && i < AppMessage -> am_NumArgs ; i++)
{
/* A correct project icon always has a
* directory lock associated, let's check it.
*/
if(AppMessage -> am_ArgList[i] . wa_Lock)
{
/* Build the project directory name. */
if(NameFromLock(AppMessage -> am_ArgList[i] . wa_Lock,ProjectName,MAX_FILENAME_LENGTH))
{
/* Add the project name. */
if(AddPart(ProjectName,AppMessage -> am_ArgList[i] . wa_Name,MAX_FILENAME_LENGTH))
{
struct DiskObject *Icon;
/* Try to read the project icon. */
if(Icon = GetDiskObject(ProjectName))
{
/* Is it really a project icon? */
if(Icon -> do_Type == WBPROJECT)
{
STRPTR Type;
/* Find the file type if any. */
if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
{
/* Is it a bookmark file? */
if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ITF"))
GotName = TRUE;
}
}
/* Free the icon data. */
FreeDiskObject(Icon);
}
}
}
}
}
}
/* Reply the notification message. */
ReplyMsg((struct Message *)AppMessage);
}
}
/* Did we get a project file name? */
if(GotName)
{
/* Get the new input string. */
InputIndex = (STRPTR)"Restore\r";
/* Return with new input. */
return(TERM_CUT);
}
else
ProjectName[0] = 0;
do
{
/* Wait for input... */
Signals = Wait(SIG_WINDOW | SIG_WORKBENCH | SIG_TIME);
/* Did we get a timeout? */
if(Signals & SIG_TIME)
{
/* Toggle the cursor state
* only if the window is
* really active.
*/
if(WindowIsActive)
{
/* Which state is the cursor currently in?
* If it's enabled, turn it off, else
* turn it on.
*/
if(CursorEnabled)
ConCursorOff();
else
ConCursorOn(CURSOR_NOCHANGE);
}
/* Wait for timer request to return. */
WaitIO((struct IORequest *)TimeRequest);
/* Restart timer. */
TimeRequest -> tr_node . io_Command = TR_ADDREQUEST;
TimeRequest -> tr_time . tv_secs = 0;
TimeRequest -> tr_time . tv_micro = SECOND / 2;
SendIO((struct IORequest *)TimeRequest);
}
}
while(!(Signals & (SIG_WINDOW | SIG_WORKBENCH)));
}
}
/* ConPrintf(const char *Format,...):
*
* Print a string on the console, including formatting.
*/
VOID
ConPrintf(const char *Format,...)
{
va_list VarArgs;
/* Build the string. */
va_start(VarArgs,Format);
vsprintf(TempBuffer,Format,VarArgs);
va_end(VarArgs);
/* Print it. */
ConWrite(TempBuffer,-1,0);
}
/* ConSwap(STRPTR a,STRPTR b,int Len):
*
* Swap the contents of two string buffers.
*/
VOID
ConSwap(STRPTR a,STRPTR b,int Len)
{
register UBYTE Temp;
while(Len--)
{
Temp = *a;
*a++ = *b;
*b++ = Temp;
}
}
/* ConInput(char *Prompt,char *Input,const int MaxLen,const Bool DoHistory):
*
* Read a line of characters.
*/
int
ConInput(char *Prompt,char *Input,const int MaxLen,const Bool DoHistory)
{
/* Control sequence buffer and length of control sequence. */
TEXT SequenceBuffer[81];
int SequenceLen;
/* Input length, current cursor position index, last history buffer. */
int Len = 0,
Index = 0,
HistoryIndex = LastHistory + 1,
i;
/* Undo buffer area. */
char *UndoBuffer;
int UndoLen,
UndoIndex;
/* The character to read. */
UBYTE Char;
/* Initial cursor X position. */
UWORD InitialCursorX = CursorX;
/* Loop flag. */
Bool Done = FALSE;
/* Prepare the undo buffer. */
UndoBuffer = malloc(MaxLen);
UndoLen = UndoIndex = 0;
/* Change the font if necessary. */
if(ThisFont != PropFont)
SetFont(RPort,ThisFont = PropFont);
/* Read until done. */
do
{
/* Get a character. */
switch(Char = ConGetChar(FALSE))
{
/* A function key, a cursor key or the help key. */
case TERM_CSI: SequenceLen = 0;
/* Read the whole sequence if possible,
* up to 80 characters will be accepted.
*/
do
SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
/* Provide null-termination. */
SequenceBuffer[SequenceLen] = 0;
/* Function key. */
if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
{
int Key;
/* Remove the terminating tilde. */
SequenceBuffer[SequenceLen - 1] = 0;
/* Make sure that the function
* key code is in reasonable
* dimensions, some custom
* keyboards have more than
* 20 function keys.
*/
if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
{
/* Is a string assigned to
* this function key?
*/
if(FunctionKeys[Key] . sb_Len)
{
Bool GotIt = FALSE;
int i;
/* Examine the string and look
* for a bar or exclamation mark
* which will terminate the
* string and produce a carriage-
* return.
*/
for(i = 0 ; i < FunctionKeys[Key] . sb_Len ; i++)
{
/* Is this the character we are looking for? */
if(FunctionKeys[Key] . sb_Buffer[i] == '|' || FunctionKeys[Key] . sb_Buffer[i] == '!')
{
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Copy the string. */
memcpy(InputBuffer,FunctionKeys[Key] . sb_Buffer,i);
/* Add the carriage-return. */
InputBuffer[i++] = '\r';
InputBuffer[i] = 0;
/* Stop the search and
* remember that we got
* a fitting string.
*/
GotIt = TRUE;
break;
}
}
/* Provide new input. */
if(GotIt)
InputIndex = InputBuffer;
else
InputIndex = FunctionKeys[Key] . sb_Buffer;
}
else
DisplayBeep(Window -> WScreen);
}
break;
}
/* Help key. */
if(DoHistory && !strcmp(SequenceBuffer,"?~"))
{
/* Which function key is pressed? */
int WhichKey = -1;
/* Do not produce any `fake' input. */
InputIndex = NULL;
/* Reset the text colour. */
ConSetColour(COLOUR_TEXT);
ConCursorOff();
/* Clear the input line. */
ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
/* Ask for the function key to
* assign a string to.
*/
ConPrintf("Function key to define: ");
ConClearEOL();
ConCursorOn(CURSOR_NOCHANGE);
/* Is the first character we get
* a control-sequence introducer?
*/
if(ConGetChar(FALSE) == TERM_CSI)
{
SequenceLen = 0;
/* Read the whole sequence if possible,
* up to 80 characters will be accepted.
*/
do
SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
/* Provide null-termination. */
SequenceBuffer[SequenceLen] = 0;
/* Did we get a function key code? */
if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
{
/* The function key we got. */
int Key;
/* Remove the terminating tilde. */
SequenceBuffer[SequenceLen - 1] = 0;
/* Get the number of the key. */
if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
WhichKey = Key;
}
}
ConCursorOff();
/* Return to input colour. */
ConSetColour(COLOUR_INPUT);
/* Did we get any key? */
if(WhichKey == -1)
ConPrintf("None.");
else
{
int Len;
/* Print the key name. */
ConPrintf("%sF%d",(WhichKey > 9) ? "Shift " : "",(WhichKey % 10) + 1);
/* Provide new line. */
ConScrollUp();
/* Set text colour. */
ConSetColour(COLOUR_TEXT);
/* Show new prompt. */
ConPrintf("Key text >");
ConCursorOn(CURSOR_NOCHANGE);
/* Return to input colour. */
ConSetColour(COLOUR_INPUT);
InputIndex = NULL;
/* Read key assignment. */
Len = ConInput("",InputBuffer,0,FALSE);
/* Set new key string. */
ConSetKey(WhichKey,InputBuffer,Len);
ConCursorOff();
}
/* Provide new line. */
ConScrollUp();
/* Set text colour. */
ConSetColour(COLOUR_TEXT);
/* Print the prompt string. */
ConPrintf(Prompt);
/* Set input colour. */
ConSetColour(COLOUR_INPUT);
/* Write the entire input line. */
ConWrite(Input,Len,0);
/* Make sure that the
* cursor is placed at
* the end of the input
* line.
*/
Index = Len;
InputIndex = NULL;
ConCursorOn(CURSOR_AVERAGE);
break;
}
/* Cursor up: recall previous line in history buffer. */
if(!strcmp(SequenceBuffer,"A"))
{
/* Are any history lines available? */
if(LastHistory != -1)
{
ConCursorOff();
/* Move cursor back
* to beginning of
* line.
*/
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line. */
ConClearEOL();
/* Go to previous history line. */
if(HistoryIndex)
HistoryIndex--;
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Determine history line length. */
if(MaxLen)
Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
else
Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
/* Copy the history line over. */
memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
/* Write the line. */
ConWrite(Input,Len,0);
ConCursorOn(CURSOR_NOCHANGE);
}
break;
}
/* Cursor down: recall next line in history buffer. */
if(!strcmp(SequenceBuffer,"B"))
{
/* Are any history lines available? */
if(LastHistory != -1)
{
ConCursorOff();
/* Are we at the end
* of the list?
*/
if(HistoryIndex < LastHistory)
{
/* Move cursor back
* to beginning of
* line.
*/
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line. */
ConClearEOL();
/* Get next history line. */
HistoryIndex++;
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Determine history line length. */
if(MaxLen)
Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
else
Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
/* Copy the history line over. */
memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
/* Write the line. */
ConWrite(Input,Len,0);
}
else
{
/* Move cursor back
* to beginning of
* line.
*/
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line. */
ConClearEOL();
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Nothing in the line buffer right now. */
Index = Len = 0;
/* Make sure that `cursor up'
* will recall the last history
* line.
*/
HistoryIndex = LastHistory + 1;
}
ConCursorOn(CURSOR_NOCHANGE);
}
break;
}
/* Shift + cursor up: recall first history line in buffer. */
if(!strcmp(SequenceBuffer,"T"))
{
/* Are any history lines available? */
if(LastHistory != -1)
{
ConCursorOff();
/* Move cursor back
* to beginning of
* line.
*/
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line. */
ConClearEOL();
/* Use the first history line. */
HistoryIndex = 0;
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Determine history line length. */
if(MaxLen)
Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
else
Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
/* Copy the history line over. */
memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
/* Write the line. */
ConWrite(Input,Len,0);
ConCursorOn(CURSOR_NOCHANGE);
}
break;
}
/* Shift + cursor down: recall last history line. */
if(!strcmp(SequenceBuffer,"S"))
{
/* Are any history lines available? */
if(LastHistory != -1)
{
ConCursorOff();
/* Move cursor back
* to beginning of
* line.
*/
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line. */
ConClearEOL();
/* Go to last line in history buffer. */
HistoryIndex = LastHistory;
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Determine history line length. */
if(MaxLen)
Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
else
Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
/* Copy the history line over. */
memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
/* Write the line. */
ConWrite(Input,Len,0);
ConCursorOn(CURSOR_NOCHANGE);
}
break;
}
/* Cursor right: move cursor to the right. */
if(!strcmp(SequenceBuffer,"C"))
{
/* Are we at the end of the line? */
if(Index < Len)
{
if(Index == Len - 1)
ConMove(ConCharWidth(Input[Index]),-1);
else
ConMove(ConCharWidth(Input[Index]),ConCharWidth(Input[Index + 1]));
Index++;
}
break;
}
/* Cursor left: move cursor to the left. */
if(!strcmp(SequenceBuffer,"D"))
{
/* Are we at the beginning of the line? */
if(Index > 0)
{
/* Update internal cursor position. */
Index--;
/* Move cursor to the left. */
ConMove(-ConCharWidth(Input[Index]),ConCharWidth(Input[Index]));
}
break;
}
/* Shift + cursor right: move cursor to end of line. */
if(!strcmp(SequenceBuffer," @"))
{
/* Are we at the end of the line? */
if(Index < Len)
{
/* Move cursor to end of line. */
ConMove(TextLength(RPort,&Input[Index],Len - Index),-1);
/* Update internal cursor position. */
Index = Len;
}
break;
}
/* Shift + cursor left: move cursor to beginning of line. */
if(!strcmp(SequenceBuffer," A"))
{
/* Are we at the beginning of the line? */
if(Index > 0)
{
/* Move cursor to beginning of line. */
if(Len)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[0]));
else
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Update internal cursor position. */
Index = 0;
}
}
break;
/* Control-A: move cursor to beginning of line. */
case TERM_BEGIN:
if(Index > 0)
{
/* Move cursor to beginning of line. */
if(Len)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[0]));
else
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Update internal cursor position. */
Index = 0;
}
break;
/* Control-Z: move cursor to end of line. */
case TERM_END: if(Index < Len)
{
/* Move cursor to end of line. */
ConMove(TextLength(RPort,&Input[Index],Len - Index),-1);
/* Update internal cursor position. */
Index = Len;
}
break;
/* Backspace: delete the character to the left
* of the cursor.
*/
case TERM_BS: if(Index > 0)
{
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Delete the character. */
if(Index == Len)
ConCharBackspace(ConCharWidth(Input[Index - 1]),-1);
else
ConCharBackspace(ConCharWidth(Input[Index - 1]),ConCharWidth(Input[Index]));
/* Move line contents. */
for(i = Index - 1 ; i < Len - 1 ; i++)
Input[i] = Input[i + 1];
/* Update internal cursor position. */
Index--;
/* Update line length. */
Len--;
}
break;
/* Delete: delete the character under the cursor. */
case TERM_DEL: if(Index < Len)
{
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Delete the character. */
if(Index == Len - 1)
ConCharDelete(CURSOR_AVERAGE);
else
ConCharDelete(ConCharWidth(Input[Index + 1]));
/* Move line contents. */
for(i = Index ; i < Len - 1 ; i++)
Input[i] = Input[i + 1];
/* Update line length. */
Len--;
}
break;
/* Control-C: copy input line. */
case TERM_COPY: if(UndoBuffer)
{
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
}
else
DisplayBeep(Window -> WScreen);
if(Len)
ClipSave(Input,Len);
break;
/* Control-Y: undo previous editing action. */
case TERM_UNDO: if(UndoBuffer)
{
int OldLen,OldIndex;
if(Len > 0)
{
/* Move to beginning of line. */
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line contents. */
ConClearEOL();
}
/* Set new cursor size. */
ConCursorOff();
ConCursorOn(CURSOR_AVERAGE);
/* Copy the input line. */
ConSwap(Input,UndoBuffer,MaxLen);
/* Restore length and index. */
OldLen = Len;
OldIndex = Index;
Len = UndoLen;
Index = UndoIndex;
UndoLen = OldLen;
UndoIndex = OldIndex;
/* Move the cursor. */
if(Index && Len)
{
if(Index == Len)
ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
else
{
if(Index)
ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
else
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
}
}
/* Redraw the input line. */
RedrawInputLine = TRUE;
}
else
DisplayBeep(Window -> WScreen);
break;
/* Control-K: delete everything from the cursor forward
* to the end of the line.
*/
case TERM_DELFWD:
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Cut off the remaining line. */
Len = Index;
/* Set new cursor size. */
ConCursorOff();
ConCursorOn(CURSOR_AVERAGE);
/* Redraw the input line. */
RedrawInputLine = TRUE;
break;
/* Control-U: delete everything from the cursor backward
* to the start of the line.
*/
case TERM_DELBCK:
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Is there anything to clear? */
if(Index > 0 && Len > 0)
{
/* Are we to clear the entire line? */
if(Index == Len)
{
/* Move to beginning of line. */
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line contents. */
ConClearEOL();
/* Nothing in the line buffer right now. */
Index = Len = 0;
}
else
{
/* Move line contents. */
for(i = 0 ; i < Len - Index ; i++)
Input[i] = Input[Index + i];
/* Move to beginning of line. */
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Update length and index. */
Len -= Index;
Index = 0;
/* Redraw the input line. */
RedrawInputLine = TRUE;
}
}
break;
/* Control-W: delete the word to the left of the cursor. */
case TERM_DELWORD:
/* Anything to delete? */
if(Len > 0 && Index > 0)
{
int Diff,Offset = Index - 1;
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Find the start of the previous word. */
for(i = Index - 1 ; i >= 0 ; i--)
{
if(i)
{
if(Input[i] == ' ')
{
Offset = i + 1;
break;
}
}
else
{
Offset = i;
break;
}
}
/* Too much to move? */
if(!(Diff = Index - Offset))
{
Diff = 1;
Offset = Index - 1;
}
/* Move the line over. */
for(i = Offset ; i < Len - Diff ; i++)
Input[i] = Input[i + Diff];
Index -= Diff;
Len -= Diff;
/* Move the cursor. */
if(Index)
ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
else
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
/* Redraw the input line. */
RedrawInputLine = TRUE;
}
break;
/* Control-\: close the window. */
case TERM_CLOSE:
if(Len > 0)
{
/* Move to beginning of line. */
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line contents. */
ConClearEOL();
/* Nothing in the line buffer right now. */
Index = Len = 0;
}
/* Drop clipboard processing. */
ClipClose();
/* Provide fake input. */
InputIndex = "Quit\r";
break;
/* Control-X: delete the entire line contents. */
case TERM_CUT: if(Len > 0)
{
ClipSave(Input,Len);
/* Save the previous input buffer contents. */
if(UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Move to beginning of line. */
if(Index)
ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
/* Clear line contents. */
ConClearEOL();
/* Nothing in the line buffer right now. */
Index = Len = 0;
}
break;
/* Carriage return: terminate input. */
case TERM_CR: Done = TRUE;
break;
/* Form feed: window was resized. */
case TERM_RESIZE:
if(Window -> Width != OldWindowWidth || Window -> Height != OldWindowHeight)
{
Bool NewPrompt = FALSE;
/* Has the width changed? */
if(Window -> Width != OldWindowWidth)
{
/* Determine new window width. */
WindowWidth = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
/* If the input line has become
* too long for the window to
* hold, trim it.
*/
if(InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
{
while(Len > 0 && InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
Len--;
/* Turn off the cursor. */
ConCursorOff();
/* Is the prompt too long? If so,
* use a single character.
*/
if(Len < 0)
{
InitialCursorX = ConCharWidth('>');
Prompt = ">";
}
/* Redraw prompt and input string. */
NewPrompt = TRUE;
}
/* Remember new window width. */
OldWindowWidth = Window -> Width;
/* Print the score line. */
scr_putscore();
}
/* Has the height changed? */
if(Window -> Height != OldWindowHeight)
{
WORD Remainder;
/* Has the window become less high?
* If so, clear the area below the
* input line.
*/
if((Remainder = Window -> Height - (Window -> BorderTop + ConNumLines * TextFontHeight + Window -> BorderBottom)) > 0)
{
SetAPen(RPort,ConBackPen);
RectFill(RPort,Window -> BorderLeft,Window -> Height - (Window -> BorderBottom + Remainder),Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
SetAPen(RPort,ConTextPen);
}
/* Turn the cursor off. */
ConCursorOff();
/* If the window has become higher,
* erase the previous prompt.
*/
if(Window -> Height > OldWindowHeight)
{
ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
ConClearEOL();
}
/* Determine new number of lines. */
ConNumLines = (Window -> Height - (Window -> BorderTop + Window -> BorderBottom)) / TextFontHeight;
/* Redraw both prompt and input string. */
NewPrompt = TRUE;
/* Remember new window height. */
OldWindowHeight = Window -> Height;
/* Clear the area below the input line. */
if((Remainder = Window -> Height - (Window -> BorderTop + ConNumLines * TextFontHeight + Window -> BorderBottom)) > 0)
{
SetAPen(RPort,ConBackPen);
RectFill(RPort,Window -> BorderLeft,Window -> Height - (Window -> BorderBottom + Remainder),Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
SetAPen(RPort,ConTextPen);
}
}
/* Are we to redraw prompt and input string? */
if(NewPrompt)
{
/* Move to bottom of window. */
ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
/* Set text colour. */
ConSetColour(COLOUR_TEXT);
/* Print the prompt string. */
ConPrintf(Prompt);
/* Set input colour. */
ConSetColour(COLOUR_INPUT);
/* Write the entire input line. */
ConWrite(Input,Len,0);
/* Clear the rest of the line. */
ConClearEOL();
/* Make sure that the
* cursor is placed at
* the end of the input
* line.
*/
Index = Len;
InputIndex = NULL;
ConCursorOn(CURSOR_AVERAGE);
}
}
break;
/* If suitable, store the character entered. */
default: if(Char >= 32 && Char <= 126)
{
/* Is there a length limit? */
if(!MaxLen || Len < MaxLen)
{
/* If the resulting string will become
* too long to fit in the window, don't
* store the new character.
*/
if(InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) < WindowWidth)
{
/* Save the previous input buffer contents. */
if(Len && UndoBuffer)
memcpy(UndoBuffer,Input,Len);
UndoLen = Len;
UndoIndex = Index;
/* Print the character. */
ConCharInsert(Char);
/* Move line contents up if
* necessary.
*/
if(Index < Len)
{
for(i = Len ; i > Index ; i--)
Input[i] = Input[i - 1];
}
/* Store the character. */
Input[Index++] = Char;
/* Update line length. */
Len++;
}
}
}
break;
}
/* Are we to redraw the input line? */
if(RedrawInputLine)
{
ConRedraw(InitialCursorX,TextFontHeight * (ConNumLines - 1),Input,Len);
RedrawInputLine = FALSE;
}
}
while(!Done);
/* Did the user enter anything? */
if(Len && DoHistory)
{
/* Move up if space is exhausted. */
if(LastHistory == HISTORY_LINES - 1)
{
/* Free first line in history buffer. */
free(HistoryBuffer[0] . sb_Buffer);
/* Move previous contents up. */
for(i = 1 ; i < HISTORY_LINES ; i++)
HistoryBuffer[i - 1] = HistoryBuffer[i];
}
else
LastHistory++;
/* Add next history line. */
if(HistoryBuffer[LastHistory] . sb_Buffer = (char *)malloc(Len))
{
/* Copy the input line. */
memcpy(HistoryBuffer[LastHistory] . sb_Buffer,Input,Len);
/* Save the line length. */
HistoryBuffer[LastHistory] . sb_Len = Len;
}
else
LastHistory--;
}
/* Drop the undo buffer. */
if(UndoBuffer)
free(UndoBuffer);
/* Close the clipboard, we don't want multiple
* lines to be returned.
*/
ClipClose();
/* Return number of characters entered. */
return(Len);
}
/* ConPrintStatus(const char *Left,const char *Right):
*
* Print the status line.
*/
VOID
ConPrintStatus(const char *Left,const char *Right)
{
int LeftLen, RightLen,
LeftWidth, RightWidth,
Width;
/* Change the font if necessary. */
if(ThisFont != PropFont)
SetFont(RPort,ThisFont = PropFont);
/* Determine lengths of both strings. */
LeftLen = strlen(Left),
RightLen = strlen(Right),
/* Determine pixel widths of both strings. */
LeftWidth = TextLength(RPort,(STRPTR)Left,LeftLen);
RightWidth = TextLength(RPort,(STRPTR)Right,RightLen);
/* Determine width of the space in between. */
Width = WindowWidth - (LeftWidth + RightWidth + 1);
/* Set the status colour. */
ConSetColour(COLOUR_STATUS);
/* Print the left part if any. */
if(LeftLen)
{
Move(RPort,Window -> BorderLeft,ThisFont -> tf_Baseline + Window -> BorderTop);
Text(RPort,(STRPTR)Left,LeftLen);
}
/* Clear the area between left and right part. */
if(Width > 0)
{
SetAPen(RPort,ConBackPen);
RectFill(RPort,LeftWidth + Window -> BorderLeft,Window -> BorderTop,LeftWidth + Width + Window -> BorderLeft,Window -> BorderTop + TextFontHeight - 1);
SetAPen(RPort,ConTextPen);
}
/* Print the right part if any. */
if(RightLen)
{
Move(RPort,Window -> Width - (RightWidth + Window -> BorderRight),Window -> BorderTop + ThisFont -> tf_Baseline);
Text(RPort,(STRPTR)Right,RightLen);
}
/* Return to previous cursor position. */
ConSetColour(COLOUR_TEXT);
}
/* ConShowRequest():
*
* Display a multiple-choice requester.
*/
LONG
ConShowRequest(const struct Window *Window,const STRPTR Text,const STRPTR Gadgets,...)
{
STATIC struct Requester BlockRequester;
struct EasyStruct Easy;
LONG Result;
ULONG IDCMP = NULL;
va_list VarArgs;
/* Clear the requester and install it, blocking
* the parent window.
*/
memset(&BlockRequester,0,sizeof(struct Requester));
Request(&BlockRequester,(struct Window *)Window);
/* Install the wait mouse pointer. */
WaitPointer((struct Window *)Window);
/* Fill in the template. */
Easy . es_StructSize = sizeof(struct EasyStruct);
Easy . es_Flags = NULL;
Easy . es_Title = (STRPTR)"Infocom";
Easy . es_TextFormat = (STRPTR)Text;
Easy . es_GadgetFormat = (STRPTR)Gadgets;
/* Display the requester. */
va_start(VarArgs,Gadgets);
Result = EasyRequestArgs((struct Window *)Window,&Easy,&IDCMP,VarArgs);
va_end(VarArgs);
/* Remove the wait mouse pointer. */
ClearPointer((struct Window *)Window);
/* Remove the blocking requester. */
EndRequest(&BlockRequester,(struct Window *)Window);
/* Return the result. */
return(Result);
}
/* ConQueryOption(int Option):
*
* Query the state of an interpreter option.
*/
Bool
ConQueryOption(int Option)
{
switch(Option)
{
case OPTION_ATTRIBUTE_ASSIGNMENTS:
if(gflags . pr_attr)
return(TRUE);
else
break;
case OPTION_ATTRIBUTE_TESTS:
if(gflags . pr_atest)
return(TRUE);
else
break;
case OPTION_ECHO:
if(gflags . echo)
return(TRUE);
else
break;
case OPTION_PAGING:
if(gflags . paged)
return(TRUE);
else
break;
case OPTION_PROMPT:
if(F1_IS_SET(B_ALT_PROMPT))
return(TRUE);
else
break;
case OPTION_STATUS:
if(gflags . pr_status)
return(TRUE);
else
break;
case OPTION_TANDY:
if(F1_IS_SET(B_TANDY))
return(TRUE);
else
break;
case OPTION_XFERS:
if(gflags . pr_xfers)
return(TRUE);
else
break;
default:
break;
}
return(FALSE);
}
/* ConUpdateMenus():
*
* Update the main menu items corresponding
* to the runtime options.
*/
VOID
ConUpdateMenus()
{
struct MenuItem *Item;
/* Block the pull-down menu. */
ConLockMenus();
/* Are object attribute assignments to be printed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ATTRIBUTE_ASSIGNMENTS,NOSUB));
if(ConQueryOption(OPTION_ATTRIBUTE_ASSIGNMENTS))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Are object attribute tests to be printed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ATTRIBUTE_TESTS,NOSUB));
if(ConQueryOption(OPTION_ATTRIBUTE_TESTS))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Is input to be echoed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ECHO,NOSUB));
if(ConQueryOption(OPTION_ECHO))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Is text paging enabled? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_PAGING,NOSUB));
if(ConQueryOption(OPTION_PAGING))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Is the alternate prompt to be displayed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_PROMPT,NOSUB));
if(ConQueryOption(OPTION_PROMPT))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Is the status line to be displayed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_STATUS,NOSUB));
if(ConQueryOption(OPTION_STATUS))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Is the Tandy license to be displayed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_TANDY,NOSUB));
if(ConQueryOption(OPTION_TANDY))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Are object transfers to be displayed? */
Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_XFERS,NOSUB));
if(ConQueryOption(OPTION_XFERS))
Item -> Flags |= CHECKED;
else
Item -> Flags &= ~CHECKED;
/* Enable the pull-down menus again. */
ConUnlockMenus();
}
/* ConLockMenus():
*
* Lock the menu strip.
*/
VOID
ConLockMenus()
{
/* Are we allowed to do what we want? */
if(NewOS)
{
if(!MenuLockCount++)
{
/* Block the menu strip. */
Window -> Flags |= WFLG_RMBTRAP;
}
}
}
/* ConUnlockMenus():
*
* Unlock the menu strip.
*/
VOID
ConUnlockMenus()
{
/* Are we allowed to do what we want? */
if(NewOS)
{
if(MenuLockCount > 0)
{
if(MenuLockCount-- == 1)
{
/* Unblock the menu strip. */
Window -> Flags &= ~WFLG_RMBTRAP;
}
}
}
}
/* ConSplitLine(char *Line,int Len,Bool ReturnPrompt):
*
* Split a hunk of text into neat little pieces.
*/
char *
ConSplitLine(char *Line,int Len,Bool ReturnPrompt)
{
LONG Width,
Indent,
Columns;
int Count,
Space;
/* Make sure that the rendering area is large enough. */
if((WindowWidth - (ConLineIndent * SpaceWidth + ConLineMargin * SpaceWidth)) / TextFontWidth < 40)
{
do
{
if(ConLineIndent)
ConLineIndent--;
if(ConLineMargin)
ConLineMargin--;
}
while(ConLineIndent && ConLineMargin && (WindowWidth - (ConLineIndent * SpaceWidth + ConLineMargin * SpaceWidth)) / TextFontWidth < 40);
}
/* Make sure to leave enough space for the user
* to type a character.
*/
if(ReturnPrompt)
{
Width = WindowWidth - (2 * TextFontWidth + SpaceWidth * ConLineMargin);
Indent = 0;
}
else
{
Width = WindowWidth - SpaceWidth * (ConLineIndent + ConLineMargin);
Indent = SpaceWidth * ConLineIndent;
}
/* Determine number of columns. */
Columns = (Width - SpaceWidth * (ConLineIndent + ConLineMargin)) / TextFontWidth;
/* Process & chop the text. */
do
{
/* Does the entire line fit? */
if(Len <= Columns)
{
/* Are we to return the
* rest of the line as
* a buffer suitable for
* printing as a prompt?
*/
if(ReturnPrompt)
return(Line);
else
ConPrintLine(Line,Count = Len,Indent);
}
else
{
/* Start with minimum values. */
Space = Count = Columns;
/* Try to find the last space in case
* the minimum width is the exact line
* size to fit which would cause the
* line to be broken at the last
* character (generally, not a pretty
* sight at all).
*/
while(Space > 0 && Line[Space] != ' ')
Space--;
/* Will another character fit? */
while(Count < Len && TextLength(RPort,(STRPTR)Line,Count + 1) < Width)
{
Count++;
/* Remember last space. */
if(Line[Count] == ' ')
Space = Count;
}
/* Print the text. */
if(Count == Len)
{
if(ReturnPrompt)
return(Line);
else
{
if(Line[Count - 1] == ' ')
ConPrintLine(Line,Count - 1,Indent);
else
ConPrintLine(Line,Count,Indent);
}
}
else
{
if(Line[Count - 1] == ' ')
ConPrintLine(Line,Count - 1,Indent);
else
{
ConPrintLine(Line,Space,Indent);
Count = Space + 1;
}
}
/* Move up. */
Line += Count;
}
/* Reduce remaining line length. */
Len -= Count;
}
while(Len > 0);
/* Return blank prompt. */
return("");
}
/* ConPrintLine(const char *Buffer,int Len,int Indent):
*
* Print a line of text.
*/
VOID
ConPrintLine(const char *Buffer,int Len,int Indent)
{
/* Is the plain text window active? */
if(!ConOutputWindow)
{
/* Scroll the screen contents up one line. */
ConScrollUp();
/* Are we to perform paging? */
if(gflags . paged)
{
int PageLength;
/* Determine current page length. */
if(ConNumStatusLines > 1 || gflags . pr_status)
PageLength = ConNumLines - ConNumStatusLines;
else
PageLength = ConNumLines;
/* Did we print enough lines already to
* show the `[More]' prompt?
*/
if(ConLinesPrinted >= PageLength - (ConLineContext + 2))
{
/* Turn on the text rendering font. */
if(ThisFont != PropFont)
SetFont(RPort,ThisFont = PropFont);
/* Set special colour. */
ConSetColour(COLOUR_SPECIAL);
/* Show the prompt. */
ConPrintf("[More]");
/* Set text colour. */
ConSetColour(COLOUR_TEXT);
/* Turn on the cursor. */
ConCursorOn(CURSOR_AVERAGE);
/* Block the pull-down menus. */
ConLockMenus();
/* Did the window size change? If so,
* go through the same number of
* actions as in the main input
* routine.
*/
while(ConGetChar(TRUE) == TERM_RESIZE)
{
if(Window -> Width != OldWindowWidth)
{
/* Remember new window width. */
OldWindowWidth = Window -> Width;
/* Determine new window dimensions. */
WindowWidth = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
/* Update score display. */
scr_putscore();
}
if(Window -> Height != OldWindowHeight)
{
WORD Remainder;
ConCursorOff();
/* If the window has become larger than
* before, remove the `[More]' prompt.
*/
if(Window -> Height > OldWindowHeight)
{
ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
ConClearEOL();
}
/* Calculate new window dimensions. */
ConNumLines = (Window -> Height - (Window -> BorderTop + Window -> BorderBottom)) / TextFontHeight;
OldWindowHeight = Window -> Height;
/* Set input colour. */
ConSetColour(COLOUR_INPUT);
/* Go to the bottom of the screen. */
ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
/* Show the prompt. */
ConPrintf("[More]");
ConClearEOL();
/* Set text colour. */
ConSetColour(COLOUR_TEXT);
/* Turn on the cursor. */
ConCursorOn(CURSOR_AVERAGE);
if((Remainder = Window -> Height - (Window -> BorderTop + ConNumLines * TextFontHeight + Window -> BorderBottom)) > 0)
{
SetAPen(RPort,ConBackPen);
RectFill(RPort,Window -> BorderLeft,Window -> Height - (Window -> BorderBottom + Remainder),Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
SetAPen(RPort,ConTextPen);
}
}
}
/* Enable the pull-down menus again. */
ConUnlockMenus();
/* Erase the `[More]' prompt. */
ConCursorOff();
ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
ConClearEOL();
/* That's all. */
ConLinesPrinted = 0;
}
else
ConLinesPrinted++;
}
}
/* Is the status window active? */
if(ConOutputWindow)
{
/* Write the string if any. */
if(Len)
{
/* Are we to change the text rendering font?
* The interpreter may want to change between
* a fixed and a proportional-spaced font.
*/
if(F2_IS_SET(B_FIXED_FONT))
{
/* Use the fixed-width font. */
if(ThisFont != FixedFont)
SetFont(RPort,ThisFont = FixedFont);
}
else
{
/* Use the proportional-spaced font. */
if(ThisFont != PropFont)
SetFont(RPort,ThisFont = PropFont);
}
/* Write the string. */
ConWrite(Buffer,Len,0);
}
/* Clear to end of line. */
ConClearEOL();
/* Update current cursor position. */
CursorY += TextFontHeight;
CursorX = 0;
}
else
{
/* Write the string if any. */
if(Len)
{
/* Are we to change the text rendering font?
* The interpreter may want to change between
* a fixed and a proportional-spaced font.
*/
if(F2_IS_SET(B_FIXED_FONT))
{
/* Use the fixed-width font. */
if(ThisFont != FixedFont)
SetFont(RPort,ThisFont = FixedFont);
}
else
{
/* Use the proportional-spaced font. */
if(ThisFont != PropFont)
SetFont(RPort,ThisFont = PropFont);
}
/* Write the string. */
ConWrite(Buffer,Len,Indent);
}
}
}
/* ConCheckStory(char *Name):
*
* Check a file to see if it's a valid type 3
* story game file.
*/
Bool
ConCheckStory(const char *Name)
{
struct FileInfoBlock *FileInfo;
Bool Result = FALSE;
/* Allocate space for fileinfo data. */
if(FileInfo = (struct FileInfoBlock *)AllocDosObjectTags(DOS_FIB,TAG_DONE))
{
BPTR FileLock;
/* Try to locate the file. */
if(FileLock = Lock((STRPTR)Name,ACCESS_READ))
{
/* Get a closer look at it. */
if(Examine(FileLock,FileInfo))
{
/* Does it look like a valid file? */
if(FileInfo -> fib_DirEntryType < 0 && FileInfo -> fib_Size > 0)
{
FILE *StoryFile;
/* Try to open the file for reading. */
if(StoryFile = fopen(Name,"rb"))
{
/* Does it look like a type 3
* story game file?
*/
if(fgetc(StoryFile) == 3)
Result = TRUE;
/* Close the file. */
fclose(StoryFile);
}
}
}
/* Release the file lock. */
UnLock(FileLock);
}
/* Free fileinfo data. */
FreeDosObject(DOS_FIB,FileInfo);
}
return(Result);
}
/* ConLocateStory(char *Directory,char *Default):
*
* Try to locate a story file in a directory.
*/
char *
ConLocateStory(const char *Directory,const char *Default)
{
char LocalBuffer[MAX_FILENAME_LENGTH];
int i,j;
/* Start with the current default name. */
if(Default[0])
{
for(j = 0 ; StoryExtensions[j] ; j++)
{
/* Copy the directory name. */
strcpy(TempBuffer,Directory);
/* Build the story file name. */
strcpy(LocalBuffer,Default);
strcat(LocalBuffer,StoryExtensions[j]);
/* Build the full path name. */
if(AddPart(TempBuffer,LocalBuffer,MAX_FILENAME_LENGTH))
{
/* Is it a valid story game file? */
if(ConCheckStory(TempBuffer))
return((char *)TempBuffer);
}
}
}
/* Run down the number of alternatives. */
for(i = 0 ; StoryNames[i] ; i++)
{
/* Run down the number of file name extensions. */
for(j = 0 ; StoryExtensions[j] ; j++)
{
/* Copy the directory name. */
strcpy(TempBuffer,Directory);
/* Build the story file name. */
strcpy(LocalBuffer,StoryNames[i]);
strcat(LocalBuffer,StoryExtensions[j]);
/* Build the full path name. */
if(AddPart(TempBuffer,LocalBuffer,MAX_FILENAME_LENGTH))
{
/* Is it a valid story game file? */
if(ConCheckStory(TempBuffer))
return((char *)TempBuffer);
}
}
}
return(NULL);
}
/* ConQueryStoryInformation(const char *Name):
*
* Query the story game header for information.
*/
VOID
ConQueryStoryInformation(const char *Name)
{
FILE *GameFile;
/* Reset information. */
StorySerial = StoryRelease = 0;
/* Try to open the file for reading. */
if(GameFile = fopen(Name,"rb"))
{
header_t GameHeader;
/* Read the game file header. */
if(fread(&GameHeader,sizeof(header_t),1,GameFile) == 1)
{
/* Is it a type 3 game? */
if(GameHeader . z_version == 3)
{
int Serial = 0,
i;
/* Calculate the serial number. */
for(i = 0 ; i < 6 ; i++)
{
Serial *= 10;
Serial += GameHeader . serial_no[i] - '0';
}
/* Try to find a corresponding
* game in the list.
*/
for(i = 0 ; SerialNumbers[i][SERIAL_INDEX] != -1 ; i++)
{
/* Do the serial and release numbers match? */
if(Serial == SerialNumbers[i][SERIAL_NUMBER] && GameHeader . release == SerialNumbers[i][SERIAL_RELEASE])
{
StorySerial = Serial;
StoryRelease = GameHeader . release;
StoryIndex = SerialNumbers[i][SERIAL_INDEX];
}
}
}
}
/* Close the story file. */
fclose(GameFile);
}
}
/* ConAbout():
*
* Display an information requester.
*/
VOID
ConAbout()
{
/* Show the information requester. */
if(StorySerial)
{
ConShowRequest(Window,"\"%s\" (%s)\nRelease %ld / Serial number %ld\nWritten by %s\n\n\"pinfo\" version %ld.%ld, Amiga release %ld.%ld\nCopyright \251 1987-1992 InfoTaskForce",
"Continue",Titles[StoryIndex],Levels[GameLevels[StoryIndex]],StoryRelease,StorySerial,Authors[StoryIndex],VERSION,PATCHLEVEL,AMIGA_VERSION,AMIGA_REVISION);
}
else
{
ConShowRequest(Window,"\"pinfo\" version %ld.%ld, Amiga release %ld.%ld\nCopyright \251 1987-1992 InfoTaskForce",
"Continue",VERSION,PATCHLEVEL,AMIGA_VERSION,AMIGA_REVISION);
}
}